home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1996 February / EnigmA AMIGA RUN 04 (1996)(G.R. Edizioni)(IT)[!][issue 1996-02][Skylink CD III].iso / earcd / comm2 / kms20src.lha / KMSXPR / kmsxpr.c < prev    next >
C/C++ Source or Header  |  1995-09-24  |  25KB  |  964 lines

  1. /**********************************
  2.  *             KMSXPR             *
  3.  **********************************/
  4.  
  5. /*************************************************************************
  6.  *
  7.  *   Copyright (C) 1995 Thomas Schwarz
  8.  *                      <kmshq@ruatha.muc.de>
  9.  *                      <Schwarz.Thomas@fhm.de>
  10.  *
  11.  *   This program is free software; you can redistribute it and/or modify
  12.  *   it under the terms of the GNU General Public License as published by
  13.  *   the Free Software Foundation; either version 2 of the License, or
  14.  *   any later version.
  15.  *
  16.  *   This program is distributed in the hope that it will be useful,
  17.  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  *   GNU General Public License for more details.
  20.  *
  21.  *   You should have received a copy of the GNU General Public License
  22.  *   along with this program; if not, write to the Free Software
  23.  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  24.  *
  25.  *************************************************************************/
  26.  
  27. #include <stdio.h>
  28. #include <string.h>
  29. #include <stdlib.h>
  30. #include <time.h>
  31. #include <exec/types.h>
  32. #include <exec/memory.h>
  33. #include <dos/dos.h>
  34. #include <dos/dostags.h>
  35. #include <dos/var.h>
  36. #include <utility/tagitem.h>
  37. #include <clib/exec_protos.h>
  38. #include <clib/dos_protos.h>
  39.  
  40. #include "xproto.h"
  41.  
  42. #define SEEK_SET 0
  43. #define SEEK_CUR 1
  44. #define SEEK_END 2
  45. #define MAXFILES 32 /* max number of files to send in one pass */
  46.  
  47. #define ACTION_QUERY 64      /* our own action */
  48.  
  49. #define LEN_DOSPATH 127
  50. #define LEN_MAXLINE 255
  51.  
  52. /********************
  53.  * Prototypes       *
  54.  ********************/
  55.  
  56. extern VOID main(UWORD argc, STRPTR *argv);
  57. extern UWORD Break(VOID);
  58. extern BOOL ParseArgs(VOID);
  59. extern LONG AUXIOStatus(VOID);
  60. extern VOID FlushInput(VOID);
  61. extern VOID Updatelog(STRPTR file, STRPTR comment);
  62. extern VOID convert_date(STRPTR a, time_t mytime);
  63. extern VOID init_xprio(BOOL batch);
  64. extern __geta4 BPTR c_fopen(STRPTR name, STRPTR mode);
  65. extern __geta4 VOID c_fclose(BPTR fileptr);
  66. extern __geta4 LONG c_fread(STRPTR buffer, LONG size, LONG count, BPTR fileptr);
  67. extern __geta4 LONG c_fwrite(STRPTR buffer, LONG size, LONG count, BPTR fileptr);
  68. extern __geta4 LONG c_finfo(STRPTR name, LONG info);
  69. extern __geta4 LONG c_fseek(BPTR fileptr, LONG position, LONG origin);
  70. extern __geta4 LONG c_sread(STRPTR buffer, LONG size, LONG timeout);
  71. extern __geta4 LONG c_swrite(STRPTR buffer, LONG size);
  72. extern __geta4 VOID c_sflush(VOID);
  73. extern __geta4 LONG c_chkabort(VOID);
  74. extern __geta4 LONG c_ffirst(STRPTR buf, STRPTR pattern);
  75. extern __geta4 LONG c_fnext(LONG fstate, STRPTR buf, STRPTR template);
  76. extern __geta4 LONG c_setserial(LONG newstatus);
  77. extern __geta4 VOID c_chkmisc(VOID);
  78. extern __geta4 LONG c_squery(VOID);
  79. extern __geta4 LONG c_unlink(STRPTR name);
  80. extern __geta4 LONG c_options(LONG n, struct xpr_option *opt[]);
  81. extern __geta4 LONG c_gets(STRPTR prompt, STRPTR buffer);
  82. extern __geta4 VOID c_update(struct XPR_UPDATE *ud);
  83.  
  84. extern LONG XProtocolSetup(struct XPR_IO *IO);
  85. extern LONG XProtocolCleanup(struct XPR_IO *IO);
  86. extern LONG XProtocolSend(struct XPR_IO *IO);
  87. extern LONG XProtocolReceive(struct XPR_IO *IO);
  88.  
  89. extern  LONG a_fopen(),  a_fclose(), a_fread(),    a_fwrite(),
  90.              a_finfo(),  a_fseek(),  a_sread(),    a_swrite(),
  91.              a_sflush(), a_update(), a_chkmisc(),  a_setserial(),
  92.              a_squery(), a_unlink(), a_chkabort(), a_options(),
  93.              a_gets(),   a_ffirst(), a_fnext();
  94.  
  95. /********************
  96.  * Global Variables *
  97.  ********************/
  98.  
  99. extern  struct DosLibrary *DOSBase;
  100.  
  101. STRPTR  Version = "\0$VER: KMSXPR 1.2 (" __COMMODORE_DATE__ ")";
  102. STRPTR  Title = "\nKMSXPR 1.2 -*- KMS File Transfer Server -*- (c)1993/94 Thomas Schwarz\n";
  103. struct  Library *XProtocolBase = NULL;
  104. struct  XPR_IO XPRIO;
  105.  
  106. struct RDArgs *RArgs = NULL;
  107. struct RDArgs *MyRDArgs = NULL;
  108.  
  109. STRPTR  FileNames[MAXFILES], LibName, LibOpts, FileList;
  110. STRPTR  LogDir = "T:", DefaultDir = "T:";
  111. TEXT    LogDate[18], LogMode[5], LogName[256];
  112. BPTR    OldCurrentDir = 0;
  113. LONG    LogBytes, LogSize, LogCps;
  114. UWORD   NumFiles = 0;
  115. BOOL    SendMode = FALSE;
  116. UBYTE   MaxFree = 0;
  117.  
  118. /*********************************
  119.  * Main                          *
  120.  *********************************/
  121.  
  122. VOID main(UWORD argc, STRPTR *argv)
  123.    {
  124.    BOOL error = FALSE;
  125.    BPTR newcurrent = NULL;
  126.    UBYTE n;
  127.  
  128.    printf(Title);
  129.  
  130.    if(!ParseArgs())
  131.       exit(10);
  132.  
  133.    if(IsInteractive(Input()))
  134.       SetMode(Input(), 1);
  135.  
  136.    /* Is DefaultDir really a directory? */
  137.  
  138.    BPTR mylock;
  139.    struct FileInfoBlock *fileinfo = (struct FileInfoBlock *)AllocMem(sizeof(struct FileInfoBlock), MEMF_PUBLIC|MEMF_CLEAR);
  140.    if(!fileinfo)
  141.       printf("\r\nOut of memory!\r\n");
  142.  
  143.    if(fileinfo && (mylock = Lock(DefaultDir, ACCESS_READ)))
  144.       {
  145.       if(Examine(mylock, fileinfo))
  146.          {
  147.          if(fileinfo->fib_DirEntryType <= 0) /* Not a directory */
  148.             {
  149.             printf("\r\n\"%s\" is not a directory!\r\n", DefaultDir);
  150.             error = TRUE;
  151.             }
  152.          }
  153.       else
  154.          {
  155.          printf("\r\nCould not Examine \"%s\"!\r\n", DefaultDir);
  156.          error = TRUE;
  157.          }
  158.  
  159.       UnLock(mylock);
  160.       }
  161.    else
  162.       {
  163.       printf("\r\nCould not Lock \"%s\"!\r\n", DefaultDir);
  164.       error = TRUE;
  165.       }
  166.  
  167.    /* Is LogDir really a directory? */
  168.  
  169.    if(fileinfo && (mylock = Lock(LogDir, ACCESS_READ)))
  170.       {
  171.       if(Examine(mylock, fileinfo))
  172.          {
  173.          if(fileinfo->fib_DirEntryType <= 0) /* Not a directory */
  174.             {
  175.             printf("\r\n\"%s\" is not a directory!\r\n", LogDir);
  176.             error = TRUE;
  177.             }
  178.          }
  179.       else
  180.          {
  181.          printf("\r\nCould not Examine \"%s\"!\r\n", LogDir);
  182.          error = TRUE;
  183.          }
  184.  
  185.       UnLock(mylock);
  186.       }
  187.    else
  188.       {
  189.       printf("\r\nCould not Lock \"%s\"!\r\n", LogDir);
  190.       error = TRUE;
  191.       }
  192.  
  193.    if(fileinfo)
  194.       FreeMem(fileinfo, sizeof(struct FileInfoBlock));
  195.  
  196.    if(!error)
  197.       {
  198.       newcurrent = Lock(DefaultDir, ACCESS_READ);
  199.       if(!newcurrent)
  200.          {
  201.          printf("\r\nFailed to set CurrentDir to \"%s\"!\r\n", DefaultDir);
  202.          error = TRUE;
  203.          }
  204.       else
  205.          OldCurrentDir = CurrentDir(newcurrent);
  206.       }
  207.  
  208.    if(!error)
  209.       {
  210.       if(SendMode)
  211.          printf("\r\nSending...\r\n");
  212.       else
  213.          printf("\r\nReceiving...\r\n");
  214.  
  215.       if(!SendMode) /* Receiving */
  216.          {
  217.          strcpy(LogMode, "Rcvd");
  218.  
  219.          if((XProtocolBase = (struct Library *)OpenLibrary(LibName, 0)))
  220.             {
  221.             if(NumFiles == 1)
  222.                init_xprio(FALSE); /* no batch mode */
  223.             else
  224.                init_xprio(TRUE); /* batch mode */
  225.  
  226.             XPRIO.xpr_filename = LibOpts;
  227.  
  228.             if(XProtocolSetup(&XPRIO))
  229.                {
  230.                XPRIO.xpr_filename = FileNames[0];
  231.                *LogName = '\0';
  232.                LogBytes = 0;
  233.                LogSize = 0;
  234.                LogCps = 0;
  235.  
  236.                if(!XProtocolReceive(&XPRIO))
  237.                   error = TRUE;
  238.  
  239.                XProtocolCleanup(&XPRIO);
  240.                }
  241.             else
  242.                {
  243.                printf("\r\nSetup error!\r\n");
  244.                error = TRUE;
  245.                }
  246.  
  247.             CloseLibrary(XProtocolBase);
  248.             }
  249.          else
  250.             {
  251.             printf("\r\nCannot open %s!\r\n", LibName);
  252.             error = TRUE;
  253.             }
  254.          }
  255.       else /* Sending */
  256.          {
  257.          strcpy(LogMode, "Sent");
  258.  
  259.          if((XProtocolBase = (struct Library *)OpenLibrary(LibName, 0)))
  260.             {
  261.             if(NumFiles > 1)
  262.                init_xprio(TRUE); /* batch mode */
  263.             else
  264.                init_xprio(FALSE); /* no batch */
  265.  
  266.             XPRIO.xpr_filename = LibOpts;
  267.  
  268.             if(XProtocolSetup(&XPRIO))
  269.                {
  270.                XPRIO.xpr_filename = NULL;
  271.                *LogName = '\0';
  272.                LogBytes = 0;
  273.                LogSize = 0;
  274.                LogCps = 0;
  275.  
  276.                if(NumFiles == 1)
  277.                   XPRIO.xpr_filename = FileNames[0];
  278.  
  279.                if(!XProtocolSend(&XPRIO))
  280.                   error = TRUE;
  281.  
  282.                XProtocolCleanup(&XPRIO);
  283.                }
  284.             else
  285.                {
  286.                printf("\r\nSetup error!\r\n");
  287.                error = TRUE;
  288.                }
  289.  
  290.             CloseLibrary(XProtocolBase);
  291.             }
  292.          else
  293.             {
  294.             printf("\r\nCannot open %s!\r\n", LibName);
  295.             error = TRUE;
  296.             }
  297.          }
  298.       }
  299.  
  300.    if(newcurrent)
  301.       {
  302.       CurrentDir(OldCurrentDir);
  303.       UnLock(newcurrent);
  304.       }
  305.  
  306.    FreeArgs(RArgs);
  307.    FreeDosObject(DOS_RDARGS, MyRDArgs);
  308.    for(n = 0; n < MaxFree; n++)
  309.       free(FileNames[n]);
  310.  
  311.    Delay(50);
  312.    FlushInput();
  313.  
  314.    if(error)
  315.       printf("\r\nTransfer failed.\r\n");
  316.    else
  317.       printf("\r\nTransfer completed.\r\n");
  318.  
  319.    if(IsInteractive(Input()))
  320.       SetMode(Input(), 0);
  321.  
  322.    exit(0);
  323.    }
  324.  
  325. /******************************************
  326.  * Break-Handler                          *
  327.  ******************************************
  328.  * I: ---                                 *
  329.  * O: 0                                   *
  330.  ******************************************/
  331.  
  332. UWORD Break(VOID)
  333.    {
  334.    return 0;
  335.    }
  336.  
  337. /****************************
  338.  * Parse Arguments          *
  339.  ****************************
  340.  * I: ---                   *
  341.  * O: Error: FALSE Ok: TRUE *
  342.  ****************************/
  343.  
  344. #define TEMPLATE "LIBRARY/A,OPTIONS/K,RECEIVE/S,SEND/S,LOGDIR/K,DEFDIR/K,LIST/K,FILES/M"
  345.  
  346. STRPTR HelpTxt = "\nUsage:\n\n" \
  347.                  "LIBRARY/A     required: name of xpr-library to use for the file transfer\n" \
  348.                  "              (e.g. \"xprzmodem.library\")\n" \
  349.                  "OPTIONS/K     optional: xpr-library options (see docs for used library)\n" \
  350.                  "              (e.g. OPTIONS=\"TN ON B16 F0 E10 AN DN KY SN RN PT:\")\n" \
  351.                  "RECEIVE/S     optional: start transfer in receive mode (default)\n" \
  352.                  "SEND/S        optional: start transfer in send mode\n" \
  353.                  "LOGDIR/K      optional: directory for transfer logging (defaults to \"T:\")\n" \
  354.                  "              (e.g. LOGDIR = DH0:Log)\n" \
  355.                  "DEFDIR/K      optional: directory for received files (default is current dir)\n" \
  356.                  "              (e.g. DEFDIR = Downloads:)\n" \
  357.                  "LIST/K        optional: file which contains, line by line, the names of\n" \
  358.                  "                        the files to be transferred including full path\n" \
  359.                  "FILES/M       optional for receiving, required for sending if no LIST given:\n" \
  360.                  "              Receiving: name of the file to be received. If none is given,\n" \
  361.                  "                         the name is taken from the sending side if possible\n" \
  362.                  "              Sending  : name(s) of the file(s) to be sent\n\n";
  363.  
  364. BOOL ParseArgs(VOID)
  365.    {
  366.    UBYTE n;
  367.    ULONG args[8];
  368.    TEXT frompath[LEN_DOSPATH+1];
  369.    TEXT fline[LEN_MAXLINE+1];
  370.    FILE *flist;
  371.  
  372.    for(n = 0; n < 8; n++)
  373.       args[n] = 0;
  374.  
  375.    LibName = NULL;
  376.    LibOpts = NULL;
  377.    FileList = NULL;
  378.    SendMode = FALSE;
  379.    NumFiles = 0;
  380.  
  381.    MyRDArgs = AllocDosObjectTags(DOS_RDARGS, TAG_DONE);
  382.    if(!MyRDArgs)
  383.       {
  384.       PrintFault(IoErr(), NULL);
  385.       return FALSE;
  386.       }
  387.  
  388.    MyRDArgs->RDA_ExtHelp = HelpTxt;
  389.  
  390.    if(!(RArgs = (struct RDArgs *)ReadArgs(TEMPLATE, args, MyRDArgs)))
  391.       {
  392.       PrintFault(IoErr(), NULL);
  393.       FreeDosObject(DOS_RDARGS, MyRDArgs);
  394.       return FALSE;
  395.       }
  396.  
  397.    if(args[0]) /* LIBRARY/A */
  398.       LibName = (STRPTR)args[0];
  399.  
  400.    if(args[1]) /* OPTIONS/K */
  401.       LibOpts = (STRPTR)args[1];
  402.  
  403.    if(args[2]) /* RECEIVE/S */
  404.       SendMode = FALSE;
  405.    else
  406.       SendMode = TRUE;
  407.  
  408.    if(args[3]) /* SEND/S */
  409.       SendMode = TRUE;
  410.    else
  411.       SendMode = FALSE;
  412.  
  413.    if(args[4]) /* LOGDIR/A */
  414.       LogDir = (STRPTR)args[4];
  415.  
  416.    if(args[5]) /* DEFDIR/A */
  417.       DefaultDir = (STRPTR)args[5];
  418.  
  419.    if(args[6]) /* LIST/K */
  420.       {
  421.       BPTR lock;
  422.  
  423.       FileList = (STRPTR)args[6];
  424.  
  425.       /* Dateien aus Filelist einlesen */
  426.  
  427.       if(!SendMode && NumFiles > 1)
  428.          {
  429.          printf("\r\nOnly batch transfer or one file in receive mode!\r\n");
  430.          FreeArgs(RArgs);
  431.          FreeDosObject(DOS_RDARGS, MyRDArgs);
  432.          return FALSE;
  433.          }
  434.  
  435.       flist = fopen(FileList, "r");
  436.       if(flist)
  437.          {
  438.          while(fgets(fline, LEN_DOSPATH, flist) && NumFiles < MAXFILES-1 && (!SendMode || NumFiles < 1))
  439.             {
  440.             *frompath = '\0';
  441.             sscanf(fline, "%s", frompath);
  442.  
  443.             if(lock = Lock(frompath, ACCESS_READ))
  444.                {
  445.                UnLock(lock);
  446.                FileNames[NumFiles++] = strdup(frompath);
  447.                MaxFree++;
  448.                }
  449.             else
  450.                printf("\r\n%s is not readable.\r\n", frompath);
  451.             }
  452.          fclose(flist);
  453.  
  454.          if(!SendMode && NumFiles > 1)
  455.             {
  456.             printf("\r\nOnly batch transfer or one file in receive mode!\r\n");
  457.             free(FileNames[0]);
  458.             free(FileNames[1]);
  459.             FreeArgs(RArgs);
  460.             FreeDosObject(DOS_RDARGS, MyRDArgs);
  461.             return FALSE;
  462.             }
  463.  
  464.          if(SendMode && !NumFiles && !args[7])
  465.             {
  466.             printf("\r\nNo files to send!?\r\n");
  467.             FreeArgs(RArgs);
  468.             FreeDosObject(DOS_RDARGS, MyRDArgs);
  469.             return FALSE;
  470.             }
  471.  
  472.          FileNames[NumFiles] = NULL;
  473.          }
  474.       else
  475.          {
  476.          printf("\r\n%s not found!\r\n", FileList);
  477.          FreeArgs(RArgs);
  478.          FreeDosObject(DOS_RDARGS, MyRDArgs);
  479.          return FALSE;
  480.          }
  481.       }
  482.  
  483.    if(args[7]) /* FILES/M */
  484.       {
  485.       STRPTR *files = (STRPTR *)args[7];
  486.       BPTR lock;
  487.       n = 0;
  488.  
  489.       /* Angegebene Files aufnehmen */
  490.  
  491.       if(!SendMode && (NumFiles > 0 || (files[0] != NULL && files[1] != NULL)))
  492.          {
  493.          printf("\r\nOnly batch transfer or one file in receive mode!\r\n");
  494.          if(NumFiles > 0)
  495.             free(FileNames[0]);
  496.          FreeArgs(RArgs);
  497.          FreeDosObject(DOS_RDARGS, MyRDArgs);
  498.          return FALSE;
  499.          }
  500.  
  501.       if(SendMode)
  502.          {
  503.          while(files[n] != NULL && NumFiles < MAXFILES-1)
  504.             {
  505.             if(lock = Lock(files[n], ACCESS_READ))
  506.                {
  507.                UnLock(lock);
  508.                FileNames[NumFiles++] = files[n];
  509.                }
  510.             else
  511.                printf("\r\n%s is not readable.\r\n", files[n]);
  512.  
  513.             n++;
  514.             }
  515.  
  516.          if(!NumFiles)
  517.             {
  518.             printf("\r\nNo files to send!?\r\n");
  519.             FreeArgs(RArgs);
  520.             FreeDosObject(DOS_RDARGS, MyRDArgs);
  521.             return FALSE;
  522.             }
  523.          }
  524.       else
  525.          FileNames[NumFiles++] = files[n];
  526.  
  527.       FileNames[NumFiles] = NULL;
  528.       }
  529.    else if(SendMode && !NumFiles)
  530.       {
  531.       printf("\r\nNo files to send!?\r\n");
  532.       FreeArgs(RArgs);
  533.       FreeDosObject(DOS_RDARGS, MyRDArgs);
  534.       return FALSE;
  535.       }
  536.  
  537.    return TRUE;
  538.    }
  539.  
  540. /*********************************
  541.  * AUXIOStatus                   *
  542.  *********************************/
  543.  
  544. LONG AUXIOStatus(VOID)
  545.    {
  546.    DoPkt(((struct FileHandle *)BADDR(Output()))->fh_Type, ACTION_QUERY, 0, 0, 0, 0, 0);
  547.  
  548.    return IoErr();
  549.    }
  550.  
  551. /****************************
  552.  * Lese-Kanal leeren        *
  553.  ****************************
  554.  * I: ---                   *
  555.  * O: ---                   *
  556.  ****************************/
  557.  
  558. /// "FlushInput"
  559.  
  560. VOID FlushInput(VOID)
  561.    {
  562.    TEXT buff[128];
  563.  
  564.    while(WaitForChar(Input(), 0) == DOSTRUE && Read(Input(), buff, sizeof(buff)) > 0);
  565.    }
  566.  
  567. ///
  568.  
  569. /*********************************************/
  570.  
  571. VOID Updatelog(STRPTR file, STRPTR comment)
  572.    {
  573.    BPTR fp;
  574.  
  575.    if(fp = Open(file, MODE_OLDFILE))
  576.       Seek(fp, 0, OFFSET_END);
  577.    else
  578.       fp = Open(file, MODE_NEWFILE);
  579.  
  580.    if(fp)
  581.       {
  582.       Write(fp, comment, strlen(comment));
  583.       Close(fp);
  584.       }
  585.    }
  586.  
  587. /*********************************************/
  588.  
  589. VOID convert_date(STRPTR a, time_t mytime)
  590.    {
  591.    struct tm *zt;
  592.  
  593.    zt = localtime(&mytime);
  594.  
  595.    sprintf(a, "%02d.%02d.%02d %02d:%02d:%02d", zt->tm_mday, zt->tm_mon+1, zt->tm_year, zt->tm_hour, zt->tm_min, zt->tm_sec);
  596.    }
  597.  
  598. /*********************************************/
  599.  
  600. VOID init_xprio(BOOL batch)
  601.    {
  602.    memset((VOID *)&XPRIO, 0, (int)sizeof(XPRIO));
  603.  
  604.    XPRIO.xpr_filename  = NULL;
  605.    XPRIO.xpr_fopen     = (VOID *)a_fopen;
  606.    XPRIO.xpr_fclose    = (VOID *)a_fclose;
  607.    XPRIO.xpr_fread     = (VOID *)a_fread;
  608.    XPRIO.xpr_fwrite    = (VOID *)a_fwrite;
  609.    XPRIO.xpr_sread     = (VOID *)a_sread;
  610.    XPRIO.xpr_swrite    = (VOID *)a_swrite;
  611.    XPRIO.xpr_sflush    = (VOID *)a_sflush;
  612.    XPRIO.xpr_update    = (VOID *)a_update;
  613.    XPRIO.xpr_chkabort  = (VOID *)a_chkabort;
  614.    XPRIO.xpr_chkmisc   = (VOID *)a_chkmisc;
  615.    XPRIO.xpr_gets      = (VOID *)a_gets;
  616.    XPRIO.xpr_setserial = (VOID *)a_setserial;
  617.  
  618.    if(batch) /* Send: several filenames given / Receive: no file given */
  619.       {
  620.       XPRIO.xpr_ffirst = (VOID *)a_ffirst;
  621.       XPRIO.xpr_fnext  = (VOID *)a_fnext;
  622.       }
  623.  
  624.    XPRIO.xpr_finfo     = (VOID *)a_finfo;
  625.    XPRIO.xpr_fseek     = (VOID *)a_fseek;
  626.  
  627.    XPRIO.xpr_extension = 3;
  628.  
  629.    XPRIO.xpr_options   = (VOID *)a_options;
  630.    XPRIO.xpr_unlink    = (VOID *)a_unlink;
  631.    XPRIO.xpr_squery    = (VOID *)a_squery;
  632.    }
  633.  
  634.  
  635. /*********************************************/
  636.  
  637. __geta4 BPTR c_fopen(STRPTR name, STRPTR mode)
  638.    {
  639.    BPTR file = NULL;
  640.    TEXT dir = mode[0], mod = mode[1];
  641.  
  642.    if(dir == 'a')
  643.       {
  644.       if(mod == '+')
  645.          file = Open(name, MODE_READWRITE);
  646.       else
  647.          file = Open(name, MODE_OLDFILE);
  648.  
  649.       if(file)
  650.          Seek(file, 0, OFFSET_END);
  651.       }
  652.    else if(dir == 'r')
  653.       {
  654.       if(mod == '+')
  655.          file = Open(name, MODE_READWRITE);
  656.       else
  657.          file = Open(name, MODE_OLDFILE);
  658.       }
  659.    else if(dir == 'w')
  660.       file = Open(name, MODE_NEWFILE);
  661.  
  662.    return(file);
  663.    }
  664.  
  665. /*********************************************/
  666.  
  667. __geta4 VOID c_fclose(BPTR fileptr)
  668.    {
  669.    Close(fileptr);
  670.    }
  671.  
  672. /*********************************************/
  673.  
  674. __geta4 LONG c_fread(STRPTR buffer, LONG size, LONG count, BPTR fileptr)
  675.    {
  676.    return Read(fileptr, buffer, size * count);
  677.    }
  678.  
  679. /*********************************************/
  680.  
  681. __geta4 LONG c_fwrite(STRPTR buffer, LONG size, LONG count, BPTR fileptr)
  682.    {
  683.    return Write(fileptr, buffer, size * count);
  684.    }
  685.  
  686. /*********************************************/
  687.  
  688. __geta4 LONG c_finfo(STRPTR name, LONG info)
  689.    {
  690.    LONG file, len = 0;
  691.  
  692.    if(info == 1)
  693.       {
  694.       if(file = Open(name, MODE_OLDFILE))
  695.          {
  696.          Seek(file, 0, OFFSET_END);
  697.          len = Seek(file, 0, OFFSET_CURRENT);
  698.          Close(file);
  699.          }
  700.       }
  701.    else if(info == 2)
  702.       len = 1; /* binary file */
  703.  
  704.    return(len);
  705.    }
  706.  
  707. /*********************************************/
  708.  
  709. __geta4 LONG c_fseek(BPTR fileptr, LONG position, LONG origin)
  710.    {
  711.    switch(origin)
  712.       {
  713.       case SEEK_SET:
  714.          Seek(fileptr, position, OFFSET_BEGINNING);
  715.          break;
  716.       case SEEK_CUR:
  717.          Seek(fileptr, position, OFFSET_CURRENT);
  718.          break;
  719.       case SEEK_END:
  720.          Seek(fileptr, position, OFFSET_END);
  721.          break;
  722.       }
  723.  
  724.    return 0;
  725.    }
  726.  
  727. /*********************************************/
  728.  
  729. /* Get char from stdio  */
  730. /* timeout is in micros */
  731. /* -1 == FATAL ERROR */
  732.  
  733. __geta4 LONG c_sread(STRPTR buffer, LONG size, LONG timeout)
  734.    {
  735.    int chars = 0, c;
  736.  
  737.    do
  738.       {
  739.       if(WaitForChar(Input(), timeout))
  740.          {
  741.          c = Read(Input(), buffer + chars, size - chars);
  742.          if(c <= 0)
  743.             return -1; /* carrier lost? EOF? breaked? */
  744.  
  745.          chars += c;
  746.  
  747.          if(!timeout)
  748.             return chars;
  749.          }
  750.       else
  751.          return chars;
  752.  
  753.       } while(chars < size);
  754.  
  755.    return chars;
  756.    }
  757.  
  758. /*********************************************/
  759.  
  760. /* Put string to stdout */
  761.  
  762. __geta4 LONG c_swrite(STRPTR buffer, LONG size)
  763.    {
  764.    return Write(Output(), buffer, size);
  765.    }
  766.  
  767. /*********************************************/
  768.  
  769. /* Flush stdin buffer */
  770.  
  771. __geta4 VOID c_sflush(VOID)
  772.    {
  773.    TEXT flushbuffer[128];
  774.  
  775.    while(WaitForChar(Input(), 0) && Read(Input(), flushbuffer, 128) > 0);
  776.    }
  777.  
  778. /*********************************************/
  779.  
  780. __geta4 LONG c_chkabort(VOID)
  781.    {
  782.    LONG state = AUXIOStatus();
  783.  
  784.    if(state == -1)
  785.       return 0; /* ACTION_QUERY not implemented */
  786.    if(state & (1 << 5))
  787.       return -1; /* carrier lost */
  788.    if(state & (1 << 10))
  789.       return -1; /* break received */
  790.  
  791.    return 0;
  792.    }
  793.  
  794. /*********************************************/
  795.  
  796. __geta4 LONG c_ffirst(STRPTR buf, STRPTR pattern)
  797.    {
  798.    if(!NumFiles)
  799.       return 0;
  800.  
  801.    strcpy(buf, FileNames[0]);
  802.  
  803.    return 1;
  804.    }
  805.  
  806. /*********************************************/
  807.  
  808. __geta4 LONG c_fnext(LONG fstate, STRPTR buf, STRPTR template)
  809.    {
  810.    if(fstate >= NumFiles)
  811.       return 0;
  812.  
  813.    strcpy(buf, FileNames[fstate]);
  814.  
  815.    return fstate + 1;
  816.    }
  817.  
  818. /*********************************************/
  819.  
  820. /* query/set serial params */
  821.  
  822. __geta4 LONG c_setserial(LONG newstatus)
  823.    {
  824.    /*
  825.         serial status longword:
  826.         .......................
  827.  
  828.         byte 0:         as the SerFlags field in IOExtSer structure.
  829.                 bit 0:  - parity on if set
  830.                 bit 1:  - parity odd if set
  831.                 bit 2:  - 7-wire protocol enabled if set
  832.                 bit 3:  - queued break if set
  833.                 bit 4:  - rad-boogie if set
  834.                 bit 5:  - shared if set
  835.                 bit 6:  - EOF mode if set
  836.                 bit 7:  - Xon/Xoff disabled if set
  837.         byte 1:         summary of other settings
  838.                 bit 0:  - enable mark/space parity if set
  839.                 bit 1:  - parity mark if set, space otherwise
  840.                 bit 2:  - 2 stop bits if set, 1 otherwise
  841.                 bit 3:  - read wordlength is 7 if set, 8 otherwise
  842.                 bit 4:  - write wordlength is 7 if set, 8 otherwise
  843.                 bit 5:  - not used
  844.                 bit 6:  - not used
  845.                 bit 7:  - not used
  846.         byte 2:         specifies one of a limited set of baud rates, as in
  847.                         preferences.h.
  848.                         -    110 baud =  0
  849.                         -    300 baud =  1
  850.                         -   1200 baud =  2
  851.                         -   2400 baud =  3
  852.                         -   4800 baud =  4
  853.                         -   9600 baud =  5
  854.                         -  19200 baud =  6
  855.                         -   midi      =  7
  856.                         -  38400 baud =  8
  857.                         -  57600 baud =  9
  858.                         -  76800 baud = 10
  859.                         - 115200 baud = 11
  860.         byte 3:         not used
  861.    */
  862.  
  863.    if(newstatus == -1L) /* query */
  864.       return 0x00050094; /* pseudo-result: 9600bps, Parity Off, 7WIRE, RAD_BOOGIE, XON/XOFF disabled, 8 Bits */
  865.    else /* set: Not implemented */
  866.       return -1L;
  867.    }
  868.  
  869. /*********************************************/
  870.  
  871. /* check miscellaneous stuff */
  872.  
  873. __geta4 VOID c_chkmisc(VOID)
  874.    {
  875.    return;
  876.    }
  877.  
  878. /*********************************************/
  879.  
  880. /* query serial input buffer */
  881.  
  882. __geta4 LONG c_squery(VOID)
  883.    {
  884.    if(WaitForChar(Input(), 0))
  885.       return IoErr();
  886.  
  887.    return 0;
  888.    }
  889.  
  890. /*********************************************/
  891.  
  892. /* delete a file */
  893.  
  894. __geta4 LONG c_unlink(STRPTR name)
  895.    {
  896.    return DeleteFile(name);
  897.    }
  898.  
  899. /*********************************************/
  900.  
  901. __geta4 LONG c_options(LONG n, struct xpr_option *opt[])
  902.    {
  903.    return 0;
  904.    }
  905.  
  906. /*********************************************/
  907.  
  908. __geta4 LONG c_gets(STRPTR prompt, STRPTR buffer)
  909.    {
  910.    *buffer = '\0';
  911.  
  912.    return 0;
  913.    }
  914.  
  915. /*********************************************/
  916.  
  917. __geta4 VOID c_update(struct XPR_UPDATE *ud)
  918.    {
  919.    TEXT buffer[128];
  920.    TEXT logpath[LEN_DOSPATH+1];
  921.    TEXT slash[2];
  922.    LONG a = ud->xpru_updatemask;
  923.  
  924.    if(a & XPRU_FILENAME)
  925.       strcpy(LogName, ud->xpru_filename);
  926.  
  927.    if(a & XPRU_FILESIZE)
  928.       LogSize = ud->xpru_filesize;
  929.  
  930.    if(a & XPRU_BYTES)
  931.       {
  932.       LogBytes = ud->xpru_bytes;
  933.  
  934.       if(LogSize != -9) /* if not already logged */
  935.          {
  936.                                         /* e.g. XModem -> No filesize given! */
  937.          if((LogBytes > 0 && LogBytes == LogSize) || LogSize == -1)
  938.             {
  939.             convert_date(LogDate, time(NULL));
  940.  
  941.             if(DefaultDir[strlen(DefaultDir)-1] != ':' && DefaultDir[strlen(DefaultDir)-1] != '/')
  942.                strcpy(slash, "/");
  943.             else
  944.                strcpy(slash, "");
  945.  
  946.             sprintf(buffer, "%s %ld %ld %s %s\n", LogName, LogSize, LogCps, LogMode, LibName);
  947.  
  948.             strcpy(logpath, LogDir);
  949.             if(logpath[strlen(logpath)-1] != ':' && logpath[strlen(logpath)-1] != '/')
  950.                strcat(logpath, "/");
  951.             strcat(logpath, "KMSXPR.LOG");
  952.  
  953.             Updatelog(logpath, buffer);
  954.  
  955.             LogSize = -9; /* already updated */
  956.             }
  957.          }
  958.       }
  959.  
  960.    if(a & XPRU_DATARATE)
  961.       LogCps = ud->xpru_datarate;
  962.    }
  963.  
  964.